<template>
  <div class="echarts" />
</template>

<style>
  .echarts {
    width: 600px;
    height: 400px;
  }
</style>

<script>
import echarts from 'echarts/lib/echarts';
import debounce from 'lodash/debounce';
import { addListener, removeListener } from 'resize-detector';
const INIT_TRIGGERS = ['theme', 'initOptions', 'autoresize'];
const REWATCH_TRIGGERS = ['manualUpdate', 'watchShallow'];

export default {
  'name': 'vEChart',
  'props': {
    'options': Object, // 相当于 echarts 文档的 setOptions(配置写在options 里面即可)
    'theme': [String, Object],
    'initOptions': Object,
    'group': String,
    'autoresize': Boolean,
    'watchShallow': Boolean,
    'manualUpdate': Boolean
  },
  data() {
    return {
      'lastArea': 0
    };
  },
  'watch': {
    group(group) {
      this.chart.group = group;
    }
  },
  'methods': {
    mergeOptions(options, notMerge, lazyUpdate) {
      if (this.manualUpdate) {
        this.manualOptions = options;
      }

      if (!this.chart) {
        this.init(options);
      } else {
        this.delegateMethod('setOption', options, notMerge, lazyUpdate);
      }
    },

    appendData(params) {
      this.delegateMethod('appendData', params);
    },

    resize(options) {
      this.delegateMethod('resize', options);
    },

    dispatchAction(payload) {
      this.delegateMethod('dispatchAction', payload);
    },

    convertToPixel(finder, value) {
      return this.delegateMethod('convertToPixel', finder, value);
    },

    convertFromPixel(finder, value) {
      return this.delegateMethod('convertFromPixel', finder, value);
    },

    containPixel(finder, value) {
      return this.delegateMethod('containPixel', finder, value);
    },

    showLoading(type, options) {
      this.delegateMethod('showLoading', type, options);
    },
    hideLoading() {
      this.delegateMethod('hideLoading');
    },
    getDataURL(options) {
      return this.delegateMethod('getDataURL', options);
    },
    getConnectedDataURL(options) {
      return this.delegateMethod('getConnectedDataURL', options);
    },
    clear() {
      this.delegateMethod('clear');
    },
    dispose() {
      this.delegateMethod('dispose');
    },
    delegateMethod(name, ...args) {
      if (!this.chart) {
        this.init();
      }
      return this.chart[name](...args);
    },
    delegateGet(methodName) {
      if (!this.chart) {
        this.init();
      }
      return this.chart[methodName]();
    },
    getArea() {
      return this.$el.offsetWidth * this.$el.offsetHeight;
    },
    init(options) {
      if (this.chart) {
        return;
      }

      const chart = echarts.init(this.$el, this.theme, this.initOptions);

      if (this.group) {
        chart.group = this.group;
      }

      chart.setOption(options || this.manualOptions || this.options || {}, true);

      Object.keys(this.$listeners).forEach(event => {
        const handler = this.$listeners[event];

        if (event.indexOf('zr:') === 0) {
          chart.getZr().on(event.slice(3), handler);
        } else {
          chart.on(event, handler);
        }
      });

      if (this.autoresize) {
        this.lastArea = this.getArea();
        this.__resizeHandler = debounce(
          () => {
            if (this.lastArea === 0) {
              // emulate initial render for initially hidden charts
              this.mergeOptions({}, true);
              this.resize();
              this.mergeOptions(this.options || this.manualOptions || {}, true);
            } else {
              this.resize();
            }
            this.lastArea = this.getArea();
          },
          100,
          { 'leading': true }
        );
        addListener(this.$el, this.__resizeHandler);
      }

      Object.defineProperties(this, {

        'width': {
          'configurable': true,
          'get': () => {
            return this.delegateGet('getWidth');
          }
        },
        'height': {
          'configurable': true,
          'get': () => {
            return this.delegateGet('getHeight');
          }
        },
        'isDisposed': {
          'configurable': true,
          'get': () => {
            return Boolean(this.delegateGet('isDisposed'));
          }
        },
        'computedOptions': {
          'configurable': true,
          'get': () => {
            return this.delegateGet('getOption');
          }
        }
      });

      this.chart = chart;
    },
    initOptionsWatcher() {
      if (this.__unwatchOptions) {
        this.__unwatchOptions();
        this.__unwatchOptions = null;
      }

      if (!this.manualUpdate) {
        this.__unwatchOptions = this.$watch(
          'options',
          (val, oldVal) => {
            if (!this.chart && val) {
              this.init();
            } else {
              this.chart.setOption(val, val !== oldVal);
            }
          },
          { 'deep': !this.watchShallow }
        );
      }
    },
    destroy() {
      if (this.autoresize) {
        removeListener(this.$el, this.__resizeHandler);
      }
      this.dispose();
      this.chart = null;
    },
    refresh() {
      if (this.chart) {
        this.destroy();
        this.init();
      }
    }
  },
  created() {
    this.initOptionsWatcher();

    INIT_TRIGGERS.forEach(prop => {
      this.$watch(
        prop,
        () => {
          this.refresh();
        },
        { 'deep': true }
      );
    });

    REWATCH_TRIGGERS.forEach(prop => {
      this.$watch(prop, () => {
        this.initOptionsWatcher();
        this.refresh();
      });
    });
  },
  mounted() {
    // auto init if `options` is already provided
    if (this.options) {
      this.init();
    }
  },
  activated() {
    if (this.autoresize) {
      this.chart && this.chart.resize();
    }
  },
  destroyed() {
    if (this.chart) {
      this.destroy();
    }
  },
  connect(group) {
    if (typeof group !== 'string') {
      group = group.map(chart => chart.chart);
    }
    echarts.connect(group);
  },
  disconnect(group) {
    echarts.disConnect(group);
  },
  getMap(mapName) {
    return echarts.getMap(mapName);
  },
  registerMap(mapName, geoJSON, specialAreas) {
    echarts.registerMap(mapName, geoJSON, specialAreas);
  },
  registerTheme(name, theme) {
    echarts.registerTheme(name, theme);
  },
  'graphic': echarts.graphic
};
</script>
